﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.ComponentModel;

namespace ClientSocketTest
{
    public class ClientSocket : IDisposable
    {
        private TcpClient tcpClient;
        private NetworkStream networkStream;

        private BackgroundWorker bgwClientReceive;
        public delegate void InformationLoger(string inform);
        InformationLoger gInformLoger;

        bool receiveMsgFlag = false;

        public ClientSocket()
        {
            receiveMsgFlag = false;
            bgwClientReceive = new BackgroundWorker();
            bgwClientReceive.WorkerReportsProgress = true;
            bgwClientReceive.WorkerSupportsCancellation = true;
            bgwClientReceive.DoWork += new DoWorkEventHandler(bgwClientReceiveDoWork);
            bgwClientReceive.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgwClientReceiveRunWorkerCompleted);

        }

        //Implement IDisposable.
        public void Dispose()
        {
            //Dispose(true);
            //GC.SuppressFinalize(this);
        }
        public void Connect(string host, int port)
        {
            if (!bgwClientReceive.IsBusy)
            {
                receiveMsgFlag = true;
                try
                {
                    tcpClient = new TcpClient();
                    tcpClient.Connect(host, port);
                    bgwClientReceive.RunWorkerAsync();
                    setInformLogOut("Connect to server.");
                }
                catch (Exception ex)
                {
                    setInformLogOut("connetc failure : " + ex.ToString());
                }
            }
            else
            {
                setInformLogOut("already Started.");
            }

        }

        public bool NetworkStreamStatus()
        {
            bool status = false;

            try
            {
                networkStream = tcpClient.GetStream();

                if (networkStream.CanRead && networkStream.CanWrite)
                {
                    status = true;
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
                status = false;
            }
            return status;
        }

        public void SendMessageString(string strMessage)
        {
            try
            {
                NetworkStream ns = tcpClient.GetStream();
                Byte[] sendBytes = Encoding.UTF8.GetBytes(strMessage);
                ns.Write(sendBytes, 0, sendBytes.Length);
            }
            catch (Exception ex)
            {
                setInformLogOut("Send message failure." + ex.ToString());
            }
        }

        public void SendMessageByteArray(byte[] byteMessage)
        {
            networkStream.Write(byteMessage, 0, byteMessage.Length);
        }
        private void bgwClientReceiveRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //這裡是程式完成時會觸發的事件，
            //這是 background執行緒結束後會觸發的值
            setInformLogOut("bgwClientReceiveRunWorkerCompleted.");
        }

        private void bgwClientReceiveDoWork(object sender, DoWorkEventArgs e)
        {
            setInformLogOut("Start Receive Message.");
            int bytesize = 0;

            while (receiveMsgFlag)
            {
                byte[] receiveMsg = ReceiveMessageByteArray(ref bytesize);
                if (bytesize > 0)
                {
                    setInformLogOut(" recelive msg :" + Encoding.UTF8.GetString(receiveMsg, 0, bytesize) + Environment.NewLine);
                }
            }
        }

        public byte[] ReceiveMessageByteArray(ref int byteSize)
        {
            bool serverCloseFlag = false;
            networkStream = tcpClient.GetStream();
            byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
            try
            {
                byteSize = networkStream.Read(bytes, 0, (int)tcpClient.ReceiveBufferSize);
            }
            catch (Exception ex)
            {
                setInformLogOut("server may close connetction : " + ex.ToString());
                serverCloseFlag = true;
                receiveMsgFlag = false;
            }
            if (serverCloseFlag)
            {
                CloseConnection();
            }
            return bytes;
        }

        public void CloseConnection()
        {
            receiveMsgFlag = false;
            if (networkStream != null)
            {
                networkStream.Close();
            }
            tcpClient.Close();
        }
        public void setInformLoger(InformationLoger log)
        {
            gInformLoger = log;
        }
        private void setInformLogOut(string inform)
        {
            if (gInformLoger == null)
            {
                return;
            }
            gInformLoger(inform);
        }
    }//public class ClientSocket
}//namespace ClientSocketTest
